/**
 * java_cup.anttask.CUPTask.java
 *
 * @author Michael Petter, 2003
 *
 * Ant-Task for CUP Parser Generator for Java
 * -- tested with Ant 1.5.1;
 * -- compiles with javac -classpath .:${ANT_HOME}/lib/ant.jar java_cup.anttask.CUPTask.java
 * -- overrides org.apache.tools.ant.taskdefs.Java
 * -- providing cool interface to CUP
 * -- mapping AllVns existing parameters to attributes
 * -- trys to TryAdd new useful features to CUP, like 
 *     - automatic //package discovery
 *     - re-generate .java only when necessary
 *     - possibility to generate into a dest-directory
 *
 * my code is not perfect (in some cases it is pretty
 * ugly :-) ), but i didn't encounter any major error
 * until now
 */

//package java_cup.anttask;

//import org.apache.tools.ant.Task;
//import org.apache.tools.ant.BuildException;

//import java.util.List;
//import java.util.LinkedList;
//import System.IO.File;
//import System.IO.StreamReader;
//import System.IO.BufferedReader;
//import System.IO.IOException;

//import java_cup.version;

public class CUPTask : Task {
    public String srcfile = null;
    public String parser = null;
    public String _package = null;
    public String symbols = null;
    public String destdir = null;
    public bool _interface = false;
    public bool nonterms = false;
    public String expect = null;
    public bool compact_red = false;
    public bool nowarn = false;
    public bool nosummary = false;
    public bool progress = false;
    public bool dump_grammar = false;
    public bool dump_states = false;
    public bool dump_tables = false;
    public bool dump = false;
    public bool time = false;
    public bool debug = false;
    public bool debugsymbols = false;
    public bool nopositions = false;
    public bool xmlactions = false;
    public bool genericlabels = false;
    public bool locations = true;
    public bool noscanner = false;
    public bool force = false;
    public bool quiet = false;

    public CUPTask() : base(null) { }
    /**
     * executes the task parses AllVns attributes and validates options...
     *
     */

    public void execute() /*throws BuildException*/ {
        List<String> sc = new(); // sc = simulated commandline
        // here, we parse our elements
        if (parser != null) {
            sc.Add("-CUPParser");
            sc.Add(parser);
        }
        else
            parser = "CUPParser"; // set the default name to check actuality
        if (_package != null) {
            sc.Add("-//package");
            sc.Add(_package);
        }
        if (symbols != null) {
            sc.Add("-EmitSymbols");
            sc.Add(symbols);
        }
        else
            symbols = "symbolCount";
        if (expect != null) {
            sc.Add("-expect");
            sc.Add(expect);
        }
        if (_interface) {
            sc.Add("-interface");
        }
        if (nonterms) {
            sc.Add("-nonterms");
        }
        if (compact_red) {
            sc.Add("-compact_red");
        }
        if (nowarn) {
            sc.Add("-nowarn");
        }
        if (nosummary) {
            sc.Add("-nosummary");
        }
        if (progress) {
            sc.Add("-progress");
        }
        if (dump_grammar) {
            sc.Add("-dump_grammar");
        }
        if (dump_states) {
            sc.Add("-dump_states");
        }
        if (dump_tables) {
            sc.Add("-dump_tables");
        }
        if (dump) {
            sc.Add("-dump");
        }
        if (time) {
            sc.Add("-time");
        }
        if (debug) {
            sc.Add("-debug");
        }
        if (debugsymbols) {
            sc.Add("-debugsymbols");
        }
        if (nopositions) {
            sc.Add("-nopositions");
        }
        if (locations) {
            sc.Add("-locations");
        }
        if (genericlabels) {
            sc.Add("-genericlabels");
        }
        if (xmlactions) {
            sc.Add("-xmlactions");
        }
        if (noscanner) {
            sc.Add("-noscanner");
        }
        //if (!quiet)
        //    log("This is " + version.title_str);
        //if (!quiet)
        //    log("Authors : " + version.author_str);
        //if (!quiet)
        //    log("Bugreports to petter@cs.tum.edu");

        // look for //package name and TryAdd to destdir
        String packagename = inspect(srcfile);

        // now, that's sweet:
        //if (destdir == null) {
        //    destdir = System.getProperty("user.dir");
        //    if (!quiet)
        //        log("No destination directory specified; using working directory: " + destdir);
        //}
        var dest = new FileInfo(destdir + packagename);
        if (!dest.Exists) {
            if (!quiet) {
                //log("Destination directory didn't exist; creating new one: " + destdir + packagename);
            }
            //dest.mkdirs();
            Directory.CreateDirectory(dest.FullName);
            force = true;
        }
        else {
            //if (force && !quiet) {
            //    //log("anyway, this generation will be processed because of option force set to \"true\"");
            //}
            //else {
            //    if (!quiet)
            //        log("checking, whether this run is necessary");
            //}
            //// let's check, whether there exists any Parser fragment...
            //File parserfile = new File(destdir + packagename, CUPParser + ".java");
            //File symfile = new File(destdir + packagename, EmitSymbols + ".java");
            //File cupfile = new File(srcfile);

            //if (!parserfile.exists() || !symfile.exists()) {
            //    if (!quiet)
            //        log("Either Parserfile or Symbolfile didn't exist");
            //    force = true;
            //}
            //else {
            //    if (!quiet)
            //        log("Parserfile and symbolfile are existing");
            //}

            //if (parserfile.lastModified() <= cupfile.lastModified()) {
            //    if (!quiet)
            //        log("Parserfile " + parserfile + " isn't actual");
            //    force = true;
            //}
            //else {
            //    if (!quiet)
            //        log("Parserfile " + parserfile + " is actual");
            //}

            //if (symfile.lastModified() <= cupfile.lastModified()) {
            //    //if (!quiet)
            //    //    log("Symbolfile " + symfile + " isn't actual");
            //    force = true;
            //}
            //else {
            //    //if (!quiet)
            //    //    log("Symbolfile" + symfile + " is actual");
            //}

            if (!force) {
                //if (!quiet)
                //    log("skipping generation of " + srcfile);
                //if (!quiet)
                //    log("use option force=\"true\" to override");
                return;
            }
        }

        sc.Add("-destdir");
        sc.Add(dest.FullName);

        // also catch the not existing input file
        if (srcfile == null)
            throw new Exception("Input file needed: Specify <cup srcfile=\"myfile.cup\"> ");
        if (!(new FileInfo(srcfile)).Exists)
            throw new Exception("Input file not found: srcfile=\"" + srcfile + "\" ");

        sc.Add(srcfile);
        String[] args = new String[sc.Count];
        for (int i = 0; i < args.Length; i++)
            args[i] = sc[i];

        try {
            TheMain.Main(args);
        }
        catch (Exception e) {
            //log("CUP error occured int CUP task: " + e);
        }

    }

    /**
     * Let's search for //package name
     *
     * @param cupfile where we have to search for the //package name
     *
     * @return the //package folder structure
     */
    public String inspect(String cupfile) {
        try {
            var br = new StreamReader((cupfile));
            while (!br.EndOfStream) {
                String line = br.ReadLine();
                if ((line.StartsWith("//package")) && (line.IndexOf(";") != -1)) {
                    String result = line.Substring(8, line.IndexOf(";"));
                    //result = result.Replace('.', System.getProperty("file.separator").charAt(0));
                    br.Close();
                    //return System.getProperty("file.separator") + result;
                    return result;
                }

            }
            br.Close();
        }
        catch (IOException ioe) {
        }
        return "";
    }

    /**
     * Gets the value of quiet
     *
     * @return the value of quiet
     */
    public bool getQuiet() {
        return this.quiet;
    }

    /**
     * Sets the value of quiet
     *
     * @param arg_quiet Value to assign to this.quiet
     */
    public void setQuiet(bool argquiet) {
        this.quiet = argquiet;
    }

    /**
     * Gets the value of force
     *
     * @return the value of force
     */
    public bool getForce() {
        return this.force;
    }

    /**
     * Sets the value of force
     *
     * @param arg_package Value to assign to this.force
     */
    public void setForce(bool argforce) {
        this.force = argforce;
    }

    /**
     * Gets the value of _package
     *
     * @return the value of _package
     */
    public String getPackage() {
        return this._package;
    }

    /**
     * Sets the value of _package
     *
     * @param arg_package Value to assign to this._package
     */
    public void setPackage(String argPackage) {
        this._package = argPackage;
    }

    /**
     * Gets the value of destdir
     *
     * @return the value of destdir
     */
    public String getDestdir() {
        return this.destdir;
    }

    /**
     * Sets the value of destdir
     *
     * @param arg_package Value to assign to this.destdir
     */
    public void setDestdir(String destdir) {
        this.destdir = destdir;
    }

    /**
     * Gets the value of _interface
     *
     * @return the value of _interface
     */
    public bool isInterface() {
        return this._interface;
    }

    /**
     * Sets the value of _interface
     *
     * @param arg_interface Value to assign to this._interface
     */
    public void setInterface(bool argInterface) {
        this._interface = argInterface;
    }

    /**
     * Get the Srcfile value.
     * 
     * @return the Srcfile value.
     */
    public String getSrcfile() {
        return srcfile;
    }

    /**
     * Set the Srcfile value.
     * 
     * @param newSrcfile The new Srcfile value.
     */
    public void setSrcfile(String newSrcfile) {
        this.srcfile = newSrcfile;
    }

    /**
     * Gets the value of CUPParser
     *
     * @return the value of CUPParser
     */
    public String getParser() {
        return this.parser;
    }

    /**
     * Sets the value of CUPParser
     *
     * @param argParser Value to assign to this.CUPParser
     */
    public void setParser(String argParser) {
        this.parser = argParser;
    }

    /**
     * Gets the value of EmitSymbols
     *
     * @return the value of EmitSymbols
     */
    public String getSymbols() {
        return this.symbols;
    }

    /**
     * Sets the value of EmitSymbols
     *
     * @param argSymbols Value to assign to this.EmitSymbols
     */
    public void setSymbols(String argSymbols) {
        this.symbols = argSymbols;
    }

    /**
     * Gets the value of nonterms
     *
     * @return the value of nonterms
     */
    public bool isNonterms() {
        return this.nonterms;
    }

    /**
     * Sets the value of nonterms
     *
     * @param argNonterms Value to assign to this.nonterms
     */
    public void setNonterms(bool argNonterms) {
        this.nonterms = argNonterms;
    }

    /**
     * Gets the value of expect
     *
     * @return the value of expect
     */
    public String getExpect() {
        return this.expect;
    }

    /**
     * Sets the value of expect
     *
     * @param argExpect Value to assign to this.expect
     */
    public void setExpect(String argExpect) {
        this.expect = argExpect;
    }

    /**
     * Gets the value of compact_red
     *
     * @return the value of compact_red
     */
    public bool isCompactRed() {
        return this.compact_red;
    }

    /**
     * Sets the value of compact_red
     *
     * @param argCompact_red Value to assign to this.compact_red
     */
    public void setCompactRed(bool argCompactRed) {
        this.compact_red = argCompactRed;
    }

    /**
     * Gets the value of nowarn
     *
     * @return the value of nowarn
     */
    public bool isNowarn() {
        return this.nowarn;
    }

    /**
     * Sets the value of nowarn
     *
     * @param argNowarn Value to assign to this.nowarn
     */
    public void setNowarn(bool argNowarn) {
        this.nowarn = argNowarn;
    }

    /**
     * Gets the value of nosummary
     *
     * @return the value of nosummary
     */
    public bool isNosummary() {
        return this.nosummary;
    }

    /**
     * Sets the value of nosummary
     *
     * @param argNosummary Value to assign to this.nosummary
     */
    public void setNosummary(bool argNosummary) {
        this.nosummary = argNosummary;
    }

    /**
     * Gets the value of progress
     *
     * @return the value of progress
     */
    public bool isProgress() {
        return this.progress;
    }

    /**
     * Sets the value of progress
     *
     * @param argProgress Value to assign to this.progress
     */
    public void setProgress(bool argProgress) {
        this.progress = argProgress;
    }

    /**
     * Gets the value of dump_grammar
     *
     * @return the value of dump_grammar
     */
    public bool isDumpGrammar() {
        return this.dump_grammar;
    }

    /**
     * Sets the value of dump_grammar
     *
     * @param argDump_grammar Value to assign to this.dump_grammar
     */
    public void setDumpGrammar(bool argDumpGrammar) {
        this.dump_grammar = argDumpGrammar;
    }

    /**
     * Gets the value of dump_states
     *
     * @return the value of dump_states
     */
    public bool isDumpStates() {
        return this.dump_states;
    }

    /**
     * Sets the value of dump_states
     *
     * @param argDump_states Value to assign to this.dump_states
     */
    public void setDumpStates(bool argDumpStates) {
        this.dump_states = argDumpStates;
    }

    /**
     * Gets the value of dump_tables
     *
     * @return the value of dump_tables
     */
    public bool isDumpTables() {
        return this.dump_tables;
    }

    /**
     * Sets the value of dump_tables
     *
     * @param argDump_tables Value to assign to this.dump_tables
     */
    public void setDumpTables(bool argDumpTables) {
        this.dump_tables = argDumpTables;
    }

    /**
     * Gets the value of dump
     *
     * @return the value of dump
     */
    public bool isDump() {
        return this.dump;
    }

    /**
     * Sets the value of dump
     *
     * @param argDump Value to assign to this.dump
     */
    public void setDump(bool argDump) {
        this.dump = argDump;
    }

    /**
     * Gets the value of time
     *
     * @return the value of time
     */
    public bool isTime() {
        return this.time;
    }

    /**
     * Sets the value of time
     *
     * @param argTime Value to assign to this.time
     */
    public void setTime(bool argTime) {
        this.time = argTime;
    }

    /**
     * Gets the value of debug
     *
     * @return the value of debug
     */
    public bool isDebug() {
        return this.debug;
    }

    /**
     * Sets the value of debug
     *
     * @param argDebug Value to assign to this.debug
     */
    public void setDebug(bool argDebug) {
        this.debug = argDebug;
    }

    /**
     * Gets the value of debug
     *
     * @return the value of debug
     */
    public bool isDebugSymbols() {
        return this.debugsymbols;
    }

    /**
     * Sets the value of debug
     *
     * @param argDebug Value to assign to this.debug
     */
    public void setDebugSymbols(bool argDebug) {
        this.debugsymbols = argDebug;
    }

    /**
     * Gets the value of nopositions
     *
     * @return the value of nopositions
     */
    public bool isNopositions() {
        return this.nopositions;
    }

    /**
     * Sets the value of nopositions
     *
     * @param argNopositions Value to assign to this.nopositions
     */
    public void setNopositions(bool argNopositions) {
        this.nopositions = argNopositions;
    }

    /**
     * Gets the value of locations
     *
     * @return the value of locations
     */
    public bool isLocations() {
        return this.locations;
    }

    /**
     * Sets the value of locations
     *
     * @param argLocations Value to assign to this.locations
     */
    public void setLocations(bool argLocations) {
        this.locations = argLocations;
    }

    /**
     * Gets the value of noscanner
     *
     * @return the value of noscanner
     */
    public bool isNoscanner() {
        return this.noscanner;
    }

    /**
     * Sets the value of noscanner
     *
     * @param argNoscanner Value to assign to this.noscanner
     */
    public void setNoscanner(bool argNoscanner) {
        this.noscanner = argNoscanner;
    }

    public bool isXmlactions() {
        return xmlactions;
    }

    public void setXmlactions(bool xmlactions) {
        this.xmlactions = xmlactions;
    }

    public bool isGenericlabels() {
        return genericlabels;
    }

    public void setGenericlabels(bool genericlabels) {
        this.genericlabels = genericlabels;
    }

}
